package com.meida.module.bus.provider.api.service;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.module.bus.client.entity.BusMaterialSrmSub;
import com.meida.module.bus.client.entity.BusPurchase;
import com.meida.module.bus.client.entity.BusReport;
import com.meida.module.bus.client.entity.srmapi.basedata.SrmContracts;
import com.meida.module.bus.client.entity.srmapi.srmtopms.*;
import com.meida.module.bus.provider.api.util.ApiConstants;
import com.meida.module.bus.provider.api.util.PmsApiUtil;
import com.meida.module.bus.provider.api.util.PmsLogUtil;
import com.meida.module.bus.provider.service.BusProjectFileService;
import com.meida.module.bus.provider.service.BusReportService;
import com.meida.module.bus.provider.service.srmservice.SrmSqlserCommonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

@Service
@RefreshScope
@Transactional(rollbackFor = Exception.class)
public class SyncSrmService {
    @Autowired
    private SyncSrmSubService syncSrmSubService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private PmsLogUtil pmsLogUtil;
    @Autowired
    private PmsApiUtil pmsApiUtil;
    @Autowired
    private SyncOASubService syncOASubService;
    @Autowired
    private BusReportService busReportService;
    @Autowired
    private BusProjectFileService busProjectFileService;

    @Value("${srm.srm01Url}")
    private String srm01Url;
    @Value("${srm.srm02Url}")
    private String srm02Url;
    @Value("${srm.srm03Url}")
    private String srm03Url;
    @Value("${srm.srm04Url}")
    private String srm04Url;
    @Value("${srm.srm05Url}")
    private String srm05Url;
    @Value("${srm.syncMaterialApplicationFileUrl}")
    private String syncMaterialApplicationFileUrl;

    // ------------------------------------------材料业务------------------------------------------------------------------

    /**
     * 材料申请-SRM01
     *
     * @param busPurchase 本次材料申请信息
     * @param userName    当前用户名
     * @return 0 正常 1 异常
     */
    public int materialRequest(BusPurchase busPurchase, String userName) throws Exception {
        try {
            if (pmsApiUtil.srmConnectionCheck()) {
                return ApiConstants.COMMON_RESULT_ZERO;
            }
            // 请求日志记录
            SrmPms01Req srmPms01Req = syncSrmSubService.getSrmPms01Req(busPurchase, userName);
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM01_LOG_MODEL_REQ, srmPms01Req.toString());

            // 发送材料请求
            SrmPms01Res srmPms01Res = restTemplate.postForObject(srm01Url, srmPms01Req, SrmPms01Res.class);

            // 异常情况
            if (ApiConstants.SYNC_API_RESULT_ZERO != srmPms01Res.getCode()) {
                // 异常日志记录
                pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM01_LOG_MODEL_RES, srmPms01Res.getMsg());
                throw new Exception("材料申请提交错误");
            }
            SrmPms01ResSub srmPms01ResSub = JSONUtil.toBean((JSONObject) JSONUtil.parseObj(srmPms01Res.getData()), SrmPms01ResSub.class);
            // 返回日志记录
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM01_LOG_MODEL_RES, srmPms01ResSub.toString());
//            syncSrmSubService.updateBusMaterialSrm(srmPms01ResSub);

            return ApiConstants.COMMON_RESULT_ZERO;

        } catch (Exception ex) {
            ex.printStackTrace();
            pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM01_LOG_MODEL_RES, ex.getMessage());
            throw ex;

        }

    }

    /**
     * 开口订单下达-SRM02
     * 【物资】【开口订单】材料申请转单申请
     * 工程师在PMS填写【开口订单】的采购数量，点击【开口订单】下达。SRM根据指令和开口合同，生成开口订单。
     *
     * @param busMaterialSrmSubs 本次下达的材料申请信息
     * @return 0 正常 1 异常
     */
    public int openOrderRequest(List<BusMaterialSrmSub> busMaterialSrmSubs) {
        try {
            StaticLog.debug("开口订单下达-SRM02----start开口订单下达-SRM02");
            if (pmsApiUtil.srmConnectionCheck()) {
                return ApiConstants.COMMON_RESULT_ZERO;
            }
            // 请求日志记录
            StaticLog.debug("开口订单下达-SRM02----组装报文---start");
            List<SrmPms02Req> srmPms02Reqs = syncSrmSubService.getSrmPms02Req(busMaterialSrmSubs);
            StaticLog.debug("开口订单下达-SRM02----组装报文---end");
            srmPms02Reqs.stream().forEach(srmPms02Req -> {
                pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM02_LOG_MODEL_REQ, srmPms02Req.toString());
                // 请求发送
                StaticLog.debug("开口订单下达-SRM02----请求发送---start");
                SrmPmsResultBody srmPmsResultBody = restTemplate.postForObject(srm02Url, srmPms02Req, SrmPmsResultBody.class);
                StaticLog.debug("开口订单下达-SRM02----请求发送---end");
                // 异常情况
                if (ApiConstants.SYNC_API_RESULT_ZERO != srmPmsResultBody.getCode()) {
                    // 异常日志记录
                    pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM02_LOG_MODEL_RES, srmPmsResultBody.getMsg());
                }
                // 返回日志记录
                pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM02_LOG_MODEL_RES, srmPmsResultBody.toString());
            });

            // 更新SRM关联子表
            syncSrmSubService.saveOrUpdateBusMaterialSrmSub(busMaterialSrmSubs);
            return ApiConstants.COMMON_RESULT_ZERO;

        } catch (Exception ex) {
            ex.printStackTrace();
            pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM02_LOG_MODEL_RES, ex.getMessage());
            throw ex;

        }

    }

    // ------------------------------------------分包业务------------------------------------------------------------------
    /**
     * 分包计划变更-SRM03
     * 【分承包】合同变更
     * 合同变更信息同步场景：
     * 1：PMS系统中，如已签订合同的材料计划发生变更。则PMS发起针对变更内容的信息同步到SRM，
     * SRM接收到同步内容后，发起合同变更，合同变更为【新建】状态。分承包业务员后续会进行修改。
     *
     * @return 0 正常 1 异常
     */
    public int planChange(Long projectId, String majorCode, String packageNo, int ver, String userName) throws Exception {
        try {
            StaticLog.debug("-----分包计划变更-SRM03-----start:");
            if (pmsApiUtil.srmConnectionCheck()) {
                return ApiConstants.COMMON_RESULT_ZERO;
            }
            StaticLog.debug("-----分包计划变更-SRM03---组装报文--start:");
            List<SrmPms03Req> srmPms03Reqs = syncSrmSubService.getSrmPms03Req(projectId, majorCode, packageNo, ver, userName);
            StaticLog.debug("-----分包计划变更-SRM03---组装报文--end:");
            if (null == srmPms03Reqs || 0 == srmPms03Reqs.size()) {
                StaticLog.debug("-----分包计划变更-SRM03---组装报文-srmPms03Reqs-为0:");
                return ApiConstants.COMMON_RESULT_ZERO;
            } else {
                StaticLog.debug("-----分包计划变更-SRM03---发送报文循环--start:");
                for (SrmPms03Req srmPms03Req : srmPms03Reqs) {
                    // 请求日志记录
                    pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM03_LOG_MODEL_REQ, srmPms03Req.toString());
                    // 发送请求
                    StaticLog.debug("-----分包计划变更-SRM03---发送请求--start:");
//                    SrmPmsResultBody srmPmsResultBody = new SrmPmsResultBody();
                    SrmPmsResultMsgBody srmPmsResultBody = restTemplate.postForObject(srm03Url, srmPms03Req, SrmPmsResultMsgBody.class);
                    StaticLog.debug("-----分包计划变更-SRM03---发送请求返回 resultBody == null --:" + (srmPmsResultBody == null));
                    StaticLog.debug("-----分包计划变更-SRM03---发送请求返回 resultBody --:" + srmPmsResultBody);
//                    StaticLog.debug(msg);
                    StaticLog.debug("-----分包计划变更-SRM03---发送请求--end:");
                    if (ApiConstants.SYNC_API_RESULT_ZERO != srmPmsResultBody.getCode()) {
                        // 异常日志记录
                        pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM03_LOG_MODEL_RES, srmPmsResultBody.getMsg());
                        throw new Exception("合同变更发起异常" + srmPmsResultBody.getMsg());
                    }
                    // 返回日志记录
                    pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM03_LOG_MODEL_RES, srmPmsResultBody.getMsg());
                }
                StaticLog.debug("-----分包计划变更-SRM03---发送报文循环--end:");
            }
            StaticLog.debug("-----分包计划变更-SRM03-----end:");
            return ApiConstants.COMMON_RESULT_ZERO;

        } catch (Exception ex) {
            ex.printStackTrace();
            pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM03_LOG_MODEL_RES, ex.getMessage());
            throw ex;

        }
    }

    /**
     * 分包计划产值录入-SRM04
     * 【分承包】对内验工月报的产值填入
     * PMS在生成完验工月包后，会以合同为单位发起送收货请求。该请求异步请求，PMS不需要同步等待SRM的回调通知。
     * SRM收到该请求后，自动生成送货单。后又财务分承包业务，进行点收审核。
     *
     * @return 0 正常 1 异常
     */
    public ResultBody busReportServiceImpl(List<BusReport> busReports, int ver) throws Exception {
        try {
            if (pmsApiUtil.srmConnectionCheck()) {
                return ResultBody.ok("产值录入完毕。");
            }

            BusMaterialSrmSub busMaterialSrmSubHeader = pmsApiUtil.getBusMaterialSrmSubForPackageForPms04(
                busReports.get(0).getMaterialId(), busReports.get(0).getSupplierId(), ver, busReports.get(0).getPackageNo());
            if (null == busMaterialSrmSubHeader || null == busMaterialSrmSubHeader.getMaterialPackageId()) {
                return ResultBody.ok("当前分包月报未下达合同。");
            }

            SrmPms04Req srmPms04Req = syncSrmSubService.getSrmPms04Req(busReports, ver);
            // 请求日志记录
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM04_LOG_MODEL_REQ, srmPms04Req.toString());

            SrmPmsResultBody srmPmsResultBody = restTemplate.postForObject(srm04Url, srmPms04Req, SrmPmsResultBody.class);

            if (ApiConstants.SYNC_API_RESULT_ZERO != srmPmsResultBody.getCode()) {
                // 异常日志记录
                pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM04_LOG_MODEL_RES, srmPmsResultBody.getMsg());
                return ResultBody.ok("产值录入失败，请联系IT管理员。");
            }

            // 返回日志记录
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM04_LOG_MODEL_RES, srmPmsResultBody.toString());

            // 结果更新到验工月报内
            busReports.stream().forEach(re->re.setSyncSrm(ApiConstants.SYNC_FLG_ON));
            busReportService.updateBatchById(busReports);

            return ResultBody.ok("产值录入完毕。");

        } catch (Exception ex) {
            ex.printStackTrace();
            pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM04_LOG_MODEL_RES, ex.getMessage());
            return ResultBody.failed(ex.getMessage());

        }

    }

    /**
     * PMS的100/200分包业务中，点击【分承包合同下达】后触发。
     * SRM接收到下达执行后，创建SRM分承包合同，该合同的状态为【新建】。
     * 分承包业务员会对【新建】的分承包合同二次编辑并提交，SRM自动生成订单
     * ✳该接口，SRM系统只要创建【新建】的分承包合同即可。
     *
     * @return 0 正常 1 异常
     */
    public int planCreate(Long projectId, String majorCode, String packageNo, int ver, String userName) throws Exception {
        try {
            if (pmsApiUtil.srmConnectionCheck()) {
                return ApiConstants.COMMON_RESULT_ZERO;
            }
            List<SrmPms05Req> srmPms05Reqs = syncSrmSubService.getSrmPms05Req(projectId, majorCode, packageNo, ver, userName);
            // 请求日志记录
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM05_LOG_MODEL_REQ, srmPms05Reqs.toString());

            List<String> errList = Lists.newArrayList();
            for (SrmPms05Req srmPms05Req : srmPms05Reqs) {
//                SrmPmsResultBody srmPmsResultBody = new SrmPmsResultBody();
                // 请求发送
                SrmPmsResultBody srmPmsResultBody = restTemplate.postForObject(srm05Url, srmPms05Req, SrmPmsResultBody.class);
                StaticLog.debug("planCreate--srmPmsResultBody:" + srmPmsResultBody);

                // 异常情况
                if (ApiConstants.SYNC_API_RESULT_ZERO != srmPmsResultBody.getCode()) {
                    // 异常日志记录
                    pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM05_LOG_MODEL_RES, srmPmsResultBody.getMsg());
                    errList.add(srmPms05Req.getVendorNo());
                    StaticLog.debug("SRM05-SRM端创建合同失败。" + srmPmsResultBody.getMsg());
                    throw new Exception(srmPmsResultBody.getMsg());
                }
                // 返回日志记录
                StaticLog.debug("planCreate---请求正常记录日志");
                pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM05_LOG_MODEL_RES, srmPmsResultBody.toString());
            }
            // 同步失败信息更新
            if (0 < errList.size()) {
                syncSrmSubService.closeSrmSyncForPackage(projectId, majorCode, packageNo, errList);
            }
            StaticLog.debug("planCreate---请求正常结束");

            return ApiConstants.COMMON_RESULT_ZERO;

        } catch (Exception ex) {
//            ex.printStackTrace();
            pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM05_LOG_MODEL_RES, ex.getMessage());
            throw ex;

        }
    }

    /**
     * 同步材料申请清单附件到SRM
     * @param purchaseId
     * @return
     * @throws Exception
     */
    public void syncMaterialApplicationFile(Long purchaseId) throws Exception {
        try {
            if (pmsApiUtil.srmConnectionCheck()) {
                return ;
            }
            // 请求日志记录
            SrmDemandPlanSyncReq srmSyncFileReq = syncSrmSubService.getSyncSrmFileReq(purchaseId);
            if(srmSyncFileReq == null) {
                return ;
            }
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM_LOG_SYNCFILE_REQ, srmSyncFileReq.toString());
            // 发送请求
            SrmSyncFileRes srmSyncFileRes = restTemplate.postForObject(syncMaterialApplicationFileUrl, srmSyncFileReq, SrmSyncFileRes.class);
            // 异常情况
            StaticLog.debug("附件同步返回-----", srmSyncFileRes);
            if(srmSyncFileRes == null) {
                return;
            }
            if (ApiConstants.SYNC_API_RESULT_ZERO != srmSyncFileRes.getCode()) {
                // 异常日志记录
                pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM_LOG_SYNCFILE_RES, srmSyncFileRes.getMsg());
            }
            SrmSyncFileResSub srmSyncFileResSub = JSONUtil.toBean((JSONObject) JSONUtil.parseObj(srmSyncFileRes.getData()), SrmSyncFileResSub.class);
            // 返回日志记录
            pmsLogUtil.saveBusSrmApiLog(ApiConstants.SRM01_LOG_MODEL_RES, srmSyncFileResSub.toString());
            busProjectFileService.updateSyncFileState(srmSyncFileResSub);
        } catch (Exception ex) {
            ex.printStackTrace();
            pmsLogUtil.saveBusSrmApiExpLog(ApiConstants.SRM_LOG_SYNCFILE_REQ, ex.getMessage());
        }
    }

}